package station;

import java.io.IOException;
import java.net.*;

public class EmpfaengerThread implements Runnable{

	private final int TEAMNR;
	private final int PORT;
	private final int UDPPORT;
	private final String stationNr;
	private boolean doCommit = true;
	private double zeitlicherSlot = 21.0;
	private double zeitlicherSlotStamp = 21.0;
	private double prevpacket;
	private int currentFrame = 1;
	private int lastFrame;
	private boolean socketClosed = false;
	private int rcv_timeout = 3100; //3,1 Sekunden timeout f�r receive im Multicast
	private final String netwInterface;
	


	//Multicast:
	InetAddress group;
	MulticastSocket socket;
	boolean running;

	//UDP
	DatagramSocket udpSocket;
	DatagramPacket udpPacket;

	//Slotbelegung
	SenderThread st;

	public EmpfaengerThread(String mcastaddress, SenderThread st, int mcport, int stationNr, int udpport, int teamNr, String netwInterface){
		this.netwInterface = netwInterface;
		this.TEAMNR = teamNr;
		this.stationNr = "team " + TEAMNR + "-" + stationNr;
		this.st = st;
		this.PORT = mcport;
		this.UDPPORT = udpport;
		try {
			socket = new MulticastSocket(PORT);
			if(!(this.netwInterface.equals(""))){		//Interface setzen
				socket.setInterface(InetAddress.getByName(netwInterface));
			}
			group = InetAddress.getByName(mcastaddress);
			socket.joinGroup(group);
			udpSocket = new DatagramSocket();		//weiter an Data Sink per udp
			socket.setSoTimeout(rcv_timeout);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		running = true;
	}

	@Override
	public void run() {
		while(running){
			try {
				//hier noch gucken, ob bekommene Daten != meiner eigenen sind

				byte[] rxBuf = new byte[33];
				DatagramPacket rxPacket = new DatagramPacket(rxBuf, rxBuf.length);
				if(!socketClosed){
					socket.receive(rxPacket);
				}else{
					socket.close();
					udpSocket.close();
				}
				//System.out.println("Interface-Name: " + socket.getInterface());
				long ankunftsZeit = System.currentTimeMillis();
				prevpacket = zeitlicherSlotStamp;
				zeitlicherSlot = (ankunftsZeit % 1000 / 50.0);
				//Zeitstempel auslesen:
				long timestamp = 0;              //Timestamp der Nachricht lesen
				for (int i=0; i<8; i++) {
					timestamp |= ((long)(rxPacket.getData()[25+i])&0xFF) << ((7-i)*8);
				}
				lastFrame = currentFrame;
				currentFrame = (int)timestamp / 1000;
				zeitlicherSlotStamp = (timestamp % 1000 / 50.0);
				if((int)prevpacket == (int)zeitlicherSlotStamp && currentFrame == lastFrame){
					System.out.println("\n\n********\n********\nKollision bei Slot: " + zeitlicherSlot + "\n********\n********\n");
				}

				//Slotbelegung setzen
				int slot = (int)rxPacket.getData()[24];
				st.setSlotFalse(slot);
			
				//Nutzdaten auslesen:
//				int stringindx = 0;
//				for(int i = 0; i<24; i++){
//					if(rxPacket.getData()[i] == 0){
//						stringindx = i;
//						break;
//					}
//				}

				byte messageBytes[] = new byte[24];
				for(int i = 0; i<24; i++){
					messageBytes[i] = rxPacket.getData()[i];
				}

				String content = new String(messageBytes);

				if(content.contains(stationNr)){					//�berpr�fen, ob Nachricht von diesem Team sind
					doCommit = false;
					System.out.println("Eigenes Paket erhalten bei " + ankunftsZeit + " auf timeSlot " + zeitlicherSlot + " N�chster slot ist: " + slot );
					rxBuf[24] = 21;
				}else{
					doCommit = true;
				}



				if(doCommit){		//Wenn nicht eigene Daten: F�r Offset ber�cksichtigen und an Sink schicken

					long offset = ankunftsZeit - timestamp;    //Differenz berechnen
//					if(setOffset > 4){
//						st.setOFFSET(offset);   //neuen Offset f�r SenderThread berechnen
//					}
//
//					setOffset++;

					//Ausgabe:
					System.out.print("ET: Nachricht: [" + content);
					System.out.printf("] Zeitstempel des angekommenen Pakets: [%d]", timestamp);
					System.out.print(" Delay Ankunft - Absendung: [" + offset);
					System.out.print("] Naechster Slot ist: [" + slot);
					System.out.print("] Angekommen bei msec [" + ankunftsZeit);
					System.out.println("] auf zeitlichem Slot [" + zeitlicherSlot + "]");

				}//doCommit
				udpPacket = new DatagramPacket(rxBuf, rxBuf.length, InetAddress.getByName("localhost"), UDPPORT);
				udpSocket.send(udpPacket);
			} catch (SocketTimeoutException ste){
				//System.out.println("Receive timed out.");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}//run
	
	public void terminate(){
		this.socketClosed = true;
		this.running = false;
		System.out.println("Empf�ngerThread...");
	}
	

}
